namespace Angelus.Oracle.Entity.Common.Entity
{
    using System;
    using System.Collections.Generic;
    using System.Data.Metadata.Edm;
    using System.Globalization;

    /// <summary>
    /// Description of OracleBuilder.
    /// </summary>
    internal class Symbol : ISqlFragment
    {
        #region Fields

        private readonly Dictionary<string, Symbol> _columns;
        private readonly string _name;

        #endregion

        #region Constructors

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="usage"></param>
        public Symbol(string name, TypeUsage usage)
        {
            this._columns = new Dictionary<string, Symbol>(StringComparer.InvariantCultureIgnoreCase);
            this.NeedsRenaming = false;
            this.IsUnnest = false;
            this._name = name;
            this.NewName = name;
            this.Type = usage;
        }

        #endregion

        #region Properties

        /// <summary>
        /// 
        /// </summary>
        public Dictionary<string, Symbol> Columns
        {
            get { return this._columns; }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool NeedsRenaming { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public bool IsUnnest { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string Name
        {
            get { return this._name; }
        }

        /// <summary>
        /// 
        /// </summary>
        public string NewName { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public TypeUsage Type { get; set; }

        #endregion

        #region ISqlFragment Implementation

        /// <summary>
        /// Write this symbol out as a string for sql. This is just
        /// the new name of the symbol (which could be the same as the old name).
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="generator"></param>
        /// <remarks>
        /// We rename columns here if necessary.
        /// </remarks>
        public void WriteSql(SqlWriter writer, SqlGenerator generator)
        {
            if (this.NeedsRenaming)
            {
                string newName;
                int sequence = generator.AllColumnNames[this.NewName];

                do
                {
                    ++sequence;
                    newName = this.Name + sequence.ToString(CultureInfo.InvariantCulture);
                } while (generator.AllColumnNames.ContainsKey(newName));

                generator.AllColumnNames[this.NewName] = sequence;

                // Prevent it from being renamed repeatedly.
                this.NeedsRenaming = false;
                this.NewName = newName;

                // Add this column name to list of known names so that there are no subsequent
                // collisions.
                generator.AllColumnNames[newName] = 0;
            }

            writer.Write(generator.QuoteIdentifier(this.NewName));
        }

        #endregion
    }
}